//! # 令牌工具
//!
//! 提供令牌生成、验证、解析等功能。

use crate::core::{SecurityError, SecurityResult, Principal};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::time::{Duration, SystemTime, UNIX_EPOCH};

/// 令牌类型
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum TokenType {
    /// 访问令牌
    Access,
    /// 刷新令牌
    Refresh,
    /// 一次性令牌
    OneTime,
    /// API密钥
    ApiKey,
    /// 会话令牌
    Session,
    /// 自定义令牌
    Custom(String),
}

/// 令牌声明
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TokenClaims {
    /// 令牌主题（用户ID）
    pub sub: String,
    /// 签发者
    pub iss: String,
    /// 受众
    pub aud: Vec<String>,
    /// 过期时间
    pub exp: u64,
    /// 签发时间
    pub iat: u64,
    /// 生效时间
    pub nbf: u64,
    /// 令牌ID
    pub jti: String,
    /// 令牌类型
    pub typ: TokenType,
    /// 自定义声明
    pub custom: HashMap<String, serde_json::Value>,
}

/// 令牌工具类
pub struct TokenUtils {
    default_issuer: String,
    default_audience: Vec<String>,
    default_ttl: Duration,
}

impl TokenUtils {
    /// 创建新的令牌工具实例
    pub fn new() -> Self {
        Self {
            default_issuer: "rustcloud-security".to_string(),
            default_audience: vec!["rustcloud".to_string()],
            default_ttl: Duration::from_secs(3600), // 1 hour
        }
    }

    /// 使用自定义配置创建令牌工具
    pub fn with_config(issuer: String, audience: Vec<String>, default_ttl: Duration) -> Self {
        Self {
            default_issuer: issuer,
            default_audience: audience,
            default_ttl,
        }
    }

    /// 创建令牌声明
    pub fn create_claims(
        &self,
        principal: &Principal,
        token_type: TokenType,
        ttl: Option<Duration>,
        custom_claims: Option<HashMap<String, serde_json::Value>>,
    ) -> SecurityResult<TokenClaims> {
        let now = SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .map_err(|e| SecurityError::TimestampValidationFailed(e.to_string()))?;

        let ttl = ttl.unwrap_or(self.default_ttl);
        let exp = now + ttl;

        let jti = self.generate_token_id()?;

        Ok(TokenClaims {
            sub: principal.id.clone(),
            iss: self.default_issuer.clone(),
            aud: self.default_audience.clone(),
            exp: exp.as_secs(),
            iat: now.as_secs(),
            nbf: now.as_secs(),
            jti,
            typ: token_type,
            custom: custom_claims.unwrap_or_default(),
        })
    }

    /// 验证令牌声明
    pub fn validate_claims(&self, claims: &TokenClaims) -> SecurityResult<()> {
        let now = SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .map_err(|e| SecurityError::TimestampValidationFailed(e.to_string()))?
            .as_secs();

        // 检查是否过期
        if now > claims.exp {
            return Err(SecurityError::ValidationFailed("Token expired".to_string()));
        }

        // 检查是否在有效期内
        if now < claims.nbf {
            return Err(SecurityError::ValidationFailed("Token not yet valid".to_string()));
        }

        // 检查签发者
        if claims.iss != self.default_issuer {
            return Err(SecurityError::ValidationFailed("Invalid issuer".to_string()));
        }

        // 检查受众
        if !claims.aud.iter().any(|aud| self.default_audience.contains(aud)) {
            return Err(SecurityError::ValidationFailed("Invalid audience".to_string()));
        }

        Ok(())
    }

    /// 从声明创建主体
    pub fn claims_to_principal(&self, claims: &TokenClaims) -> SecurityResult<Principal> {
        let mut principal = Principal::new(
            claims.sub.clone(),
            claims.custom.get("name")
                .and_then(|v| v.as_str())
                .unwrap_or(&claims.sub)
                .to_string(),
            claims.custom.get("principal_type")
                .and_then(|v| v.as_str())
                .map(|t| match t {
                    "admin" => crate::core::PrincipalType::Admin,
                    "service" => crate::core::PrincipalType::Service,
                    "system" => crate::core::PrincipalType::System,
                    "anonymous" => crate::core::PrincipalType::Anonymous,
                    custom => crate::core::PrincipalType::Custom(custom.to_string()),
                })
                .unwrap_or(crate::core::PrincipalType::User),
        );

        // 添加角色
        if let Some(roles) = claims.custom.get("roles") {
            if let Some(roles_array) = roles.as_array() {
                for role in roles_array {
                    if let Some(role_str) = role.as_str() {
                        principal = principal.add_role(role_str.to_string());
                    }
                }
            }
        }

        // 添加权限
        if let Some(permissions) = claims.custom.get("permissions") {
            if let Some(permissions_array) = permissions.as_array() {
                for permission in permissions_array {
                    if let Some(permission_str) = permission.as_str() {
                        principal = principal.add_permission(permission_str.to_string());
                    }
                }
            }
        }

        // 设置过期时间
        let expires_at = UNIX_EPOCH + Duration::from_secs(claims.exp);
        principal = principal.with_expiry(expires_at);

        // 添加自定义属性
        for (key, value) in &claims.custom {
            if !["roles", "permissions", "principal_type", "name"].contains(&key.as_str()) {
                if let Some(string_value) = value.as_str() {
                    principal = principal.add_attribute(key.clone(), string_value.to_string());
                }
            }
        }

        Ok(principal)
    }

    /// 从主体创建声明的自定义字段
    pub fn principal_to_custom_claims(&self, principal: &Principal) -> HashMap<String, serde_json::Value> {
        let mut custom = HashMap::new();

        // 添加基本信息
        custom.insert("name".to_string(), serde_json::Value::String(principal.name.clone()));
        custom.insert("principal_type".to_string(), serde_json::Value::String(
            match &principal.principal_type {
                crate::core::PrincipalType::User => "user".to_string(),
                crate::core::PrincipalType::Admin => "admin".to_string(),
                crate::core::PrincipalType::Service => "service".to_string(),
                crate::core::PrincipalType::System => "system".to_string(),
                crate::core::PrincipalType::Anonymous => "anonymous".to_string(),
                crate::core::PrincipalType::Custom(t) => t.clone(),
            }
        ));

        // 添加角色
        if !principal.roles.is_empty() {
            let roles: Vec<serde_json::Value> = principal.roles.iter()
                .map(|r| serde_json::Value::String(r.clone()))
                .collect();
            custom.insert("roles".to_string(), serde_json::Value::Array(roles));
        }

        // 添加权限
        if !principal.permissions.is_empty() {
            let permissions: Vec<serde_json::Value> = principal.permissions.iter()
                .map(|p| serde_json::Value::String(p.clone()))
                .collect();
            custom.insert("permissions".to_string(), serde_json::Value::Array(permissions));
        }

        // 添加自定义属性
        for (key, value) in &principal.attributes {
            custom.insert(key.clone(), serde_json::Value::String(value.clone()));
        }

        custom
    }

    /// 生成令牌ID
    pub fn generate_token_id(&self) -> SecurityResult<String> {
        use crate::utils::CryptoUtils;
        let crypto = CryptoUtils::new();
        let uuid = crypto.generate_uuid();
        Ok(uuid.replace('-', ""))
    }

    /// 生成简单的随机令牌
    pub fn generate_simple_token(&self, length: usize) -> SecurityResult<String> {
        use crate::utils::CryptoUtils;
        let crypto = CryptoUtils::new();
        crypto.generate_secure_token(length)
            .map_err(|e| SecurityError::RandomGenerationFailed(e.to_string()))
    }

    /// 生成API密钥
    pub fn generate_api_key(&self, prefix: Option<&str>) -> SecurityResult<String> {
        let token = self.generate_simple_token(32)?;
        match prefix {
            Some(p) => Ok(format!("{}_{}", p, token)),
            None => Ok(format!("ak_{}", token)),
        }
    }

    /// 解析API密钥前缀
    pub fn parse_api_key_prefix(&self, api_key: &str) -> Option<String> {
        if let Some(underscore_pos) = api_key.find('_') {
            Some(api_key[..underscore_pos].to_string())
        } else {
            None
        }
    }

    /// 验证API密钥格式
    pub fn validate_api_key_format(&self, api_key: &str) -> bool {
        // 检查基本格式：prefix_token
        if !api_key.contains('_') {
            return false;
        }

        let parts: Vec<&str> = api_key.split('_').collect();
        if parts.len() != 2 {
            return false;
        }

        let prefix = parts[0];
        let token = parts[1];

        // 验证前缀：2-8个字母
        if prefix.len() < 2 || prefix.len() > 8 || !prefix.chars().all(|c| c.is_ascii_alphabetic()) {
            return false;
        }

        // 验证令牌：16-64个字母数字字符
        if token.len() < 16 || token.len() > 64 || !token.chars().all(|c| c.is_ascii_alphanumeric()) {
            return false;
        }

        true
    }

    /// 计算令牌熵值（安全强度评估）
    pub fn calculate_token_entropy(&self, token: &str) -> f64 {
        let mut char_counts = HashMap::new();
        for c in token.chars() {
            *char_counts.entry(c).or_insert(0) += 1;
        }

        let length = token.len() as f64;
        let mut entropy = 0.0;

        for count in char_counts.values() {
            let probability = *count as f64 / length;
            entropy -= probability * probability.log2();
        }

        entropy
    }

    /// 检查令牌是否具有足够的安全强度
    pub fn is_token_secure(&self, token: &str) -> bool {
        // 基本长度检查
        if token.len() < 16 {
            return false;
        }

        // 熵值检查
        let entropy = self.calculate_token_entropy(token);
        if entropy < 3.0 {
            return false;
        }

        // 字符集多样性检查
        let has_upper = token.chars().any(|c| c.is_ascii_uppercase());
        let has_lower = token.chars().any(|c| c.is_ascii_lowercase());
        let has_digit = token.chars().any(|c| c.is_ascii_digit());

        has_upper && has_lower && has_digit
    }

    /// 屏蔽令牌敏感部分（用于日志记录）
    pub fn mask_token(&self, token: &str) -> String {
        use crate::utils::CryptoUtils;
        let crypto = CryptoUtils::new();
        crypto.mask_sensitive_data(token, '*', 4)
    }

    /// 获取令牌剩余有效时间
    pub fn get_token_ttl(&self, claims: &TokenClaims) -> SecurityResult<Duration> {
        let now = SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .map_err(|e| SecurityError::TimestampValidationFailed(e.to_string()))?
            .as_secs();

        if now >= claims.exp {
            Ok(Duration::from_secs(0)) // 已过期
        } else {
            Ok(Duration::from_secs(claims.exp - now))
        }
    }

    /// 检查令牌是否即将过期
    pub fn is_token_expiring_soon(&self, claims: &TokenClaims, threshold: Duration) -> SecurityResult<bool> {
        let ttl = self.get_token_ttl(claims)?;
        Ok(ttl <= threshold)
    }

    /// 创建令牌指纹（用于撤销列表）
    pub fn create_token_fingerprint(&self, token: &str) -> SecurityResult<String> {
        use crate::utils::CryptoUtils;
        let crypto = CryptoUtils::new();
        crypto.sha256(token)
    }
}

impl Default for TokenUtils {
    fn default() -> Self {
        Self::new()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::core::PrincipalType;

    #[test]
    fn test_token_utils_creation() {
        let token_utils = TokenUtils::new();
        assert_eq!(token_utils.default_issuer, "rustcloud-security");
        assert_eq!(token_utils.default_audience, vec!["rustcloud"]);
    }

    #[test]
    fn test_create_claims() {
        let token_utils = TokenUtils::new();
        let principal = Principal::new(
            "user123".to_string(),
            "John Doe".to_string(),
            PrincipalType::User,
        );

        let claims = token_utils.create_claims(
            &principal,
            TokenType::Access,
            Some(Duration::from_secs(1800)),
            None,
        ).unwrap();

        assert_eq!(claims.sub, "user123");
        assert_eq!(claims.iss, "rustcloud-security");
        assert_eq!(claims.typ, TokenType::Access);
        assert!(claims.exp > claims.iat);
    }

    #[test]
    fn test_validate_claims() {
        let token_utils = TokenUtils::new();
        let principal = Principal::new(
            "user123".to_string(),
            "John Doe".to_string(),
            PrincipalType::User,
        );

        let claims = token_utils.create_claims(
            &principal,
            TokenType::Access,
            Some(Duration::from_secs(1800)),
            None,
        ).unwrap();

        // 应该验证成功
        assert!(token_utils.validate_claims(&claims).is_ok());

        // 测试过期的令牌
        let mut expired_claims = claims.clone();
        expired_claims.exp = expired_claims.iat - 1;
        assert!(token_utils.validate_claims(&expired_claims).is_err());

        // 测试无效的签发者
        let mut invalid_issuer_claims = claims.clone();
        invalid_issuer_claims.iss = "invalid-issuer".to_string();
        assert!(token_utils.validate_claims(&invalid_issuer_claims).is_err());
    }

    #[test]
    fn test_principal_claims_conversion() {
        let token_utils = TokenUtils::new();
        let original_principal = Principal::new(
            "user123".to_string(),
            "John Doe".to_string(),
            PrincipalType::User,
        )
        .add_role("user".to_string())
        .add_role("editor".to_string())
        .add_permission("read:posts".to_string())
        .add_permission("write:posts".to_string())
        .add_attribute("department".to_string(), "Engineering".to_string());

        // 转换为自定义声明
        let custom_claims = token_utils.principal_to_custom_claims(&original_principal);
        assert!(custom_claims.contains_key("roles"));
        assert!(custom_claims.contains_key("permissions"));
        assert!(custom_claims.contains_key("department"));

        // 创建完整的声明
        let claims = token_utils.create_claims(
            &original_principal,
            TokenType::Access,
            None,
            Some(custom_claims),
        ).unwrap();

        // 从声明恢复主体
        let recovered_principal = token_utils.claims_to_principal(&claims).unwrap();

        assert_eq!(recovered_principal.id, original_principal.id);
        assert_eq!(recovered_principal.name, original_principal.name);
        assert!(recovered_principal.has_role("user"));
        assert!(recovered_principal.has_role("editor"));
        assert!(recovered_principal.has_permission("read:posts"));
        assert!(recovered_principal.has_permission("write:posts"));
        assert_eq!(recovered_principal.get_attribute("department"), Some("Engineering"));
    }

    #[test]
    fn test_api_key_generation() {
        let token_utils = TokenUtils::new();
        
        let api_key1 = token_utils.generate_api_key(None).unwrap();
        let api_key2 = token_utils.generate_api_key(Some("test")).unwrap();

        assert!(api_key1.starts_with("ak_"));
        assert!(api_key2.starts_with("test_"));
        assert_ne!(api_key1, api_key2);

        // 验证格式
        assert!(token_utils.validate_api_key_format(&api_key1));
        assert!(token_utils.validate_api_key_format(&api_key2));

        // 解析前缀
        assert_eq!(token_utils.parse_api_key_prefix(&api_key1), Some("ak".to_string()));
        assert_eq!(token_utils.parse_api_key_prefix(&api_key2), Some("test".to_string()));
    }

    #[test]
    fn test_token_security() {
        let token_utils = TokenUtils::new();
        
        let secure_token = token_utils.generate_simple_token(32).unwrap();
        assert!(token_utils.is_token_secure(&secure_token));

        let weak_token = "123456";
        assert!(!token_utils.is_token_secure(weak_token));

        let short_token = "abc";
        assert!(!token_utils.is_token_secure(short_token));
    }

    #[test]
    fn test_token_entropy() {
        let token_utils = TokenUtils::new();
        
        let high_entropy_token = "aB3dE7gH1jK9mN2pQ5rS8tU";
        let low_entropy_token = "aaaaaaaaaaaaaaaa";

        let high_entropy = token_utils.calculate_token_entropy(high_entropy_token);
        let low_entropy = token_utils.calculate_token_entropy(low_entropy_token);

        assert!(high_entropy > low_entropy);
    }

    #[test]
    fn test_token_masking() {
        let token_utils = TokenUtils::new();
        let token = "abcdefghijklmnopqrstuvwxyz";
        let masked = token_utils.mask_token(token);

        assert!(masked.starts_with("abcd"));
        assert!(masked.ends_with("wxyz"));
        assert!(masked.contains('*'));
    }

    #[test]
    fn test_token_ttl() {
        let token_utils = TokenUtils::new();
        let principal = Principal::new(
            "user123".to_string(),
            "John Doe".to_string(),
            PrincipalType::User,
        );

        let claims = token_utils.create_claims(
            &principal,
            TokenType::Access,
            Some(Duration::from_secs(3600)),
            None,
        ).unwrap();

        let ttl = token_utils.get_token_ttl(&claims).unwrap();
        assert!(ttl.as_secs() > 3500 && ttl.as_secs() <= 3600);

        let is_expiring = token_utils.is_token_expiring_soon(&claims, Duration::from_secs(7200)).unwrap();
        assert!(is_expiring); // 3600 < 7200, so it's expiring soon
    }

    #[test]
    fn test_token_fingerprint() {
        let token_utils = TokenUtils::new();
        let token = "test_token_123";
        
        let fingerprint1 = token_utils.create_token_fingerprint(token).unwrap();
        let fingerprint2 = token_utils.create_token_fingerprint(token).unwrap();

        assert_eq!(fingerprint1, fingerprint2); // Should be consistent
        assert_eq!(fingerprint1.len(), 64); // SHA256 hash length
    }
}